#include <iostream>
#include <memory>
#include <string>

#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>

#include "grpc_ex.grpc.pb.h"

using grpc::CallbackServerContext;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerUnaryReactor;
using grpc::Status;

using grpc_ex::MainGateway;
using grpc_ex::Main_Ctrl_Takeoff_Reply;
using grpc_ex::Main_Ctrl_Takeoff_Request;
using grpc_ex::Main_Ctrl_Land_Reply;
using grpc_ex::Main_Ctrl_Land_Request;
using grpc_ex::Main_Ctrl_RTL_Reply;
using grpc_ex::Main_Ctrl_RTL_Request;
using grpc_ex::Main_Ctrl_PositionGlobal_Reply;
using grpc_ex::Main_Ctrl_PositionGlobal_Request;
using grpc_ex::Main_Ctrl_PositionNED_Reply;
using grpc_ex::Main_Ctrl_PositionNED_Request;

class GreeterServiceImpl final : public MainGateway::CallbackService {

  ServerUnaryReactor* Ctrl_Takeoff(CallbackServerContext* context,
                                  const Main_Ctrl_Takeoff_Request* request,
                                  Main_Ctrl_Takeoff_Reply* reply) override {
    reply->set_message("CMD : Takeoff : Accept");

    std::cout << "Takeoff\t" << request->alt_m() << std::endl;

    ServerUnaryReactor* reactor = context->DefaultReactor();
    reactor->Finish(Status::OK);
    return reactor;
  }
  ServerUnaryReactor* Ctrl_Land(CallbackServerContext* context,
                                  const Main_Ctrl_Land_Request* request,
                                  Main_Ctrl_Land_Reply* reply) override {
    reply->set_message("CMD : Land : Accept");

    ServerUnaryReactor* reactor = context->DefaultReactor();
    reactor->Finish(Status::OK);
    return reactor;
  }
  ServerUnaryReactor* Ctrl_RTL(CallbackServerContext* context,
                                  const Main_Ctrl_RTL_Request* request,
                                  Main_Ctrl_RTL_Reply* reply) override {
    reply->set_message("CMD : RTL : Accept");

    ServerUnaryReactor* reactor = context->DefaultReactor();
    reactor->Finish(Status::OK);
    return reactor;
  }
  ServerUnaryReactor* Ctrl_PositionGlobal(CallbackServerContext* context,
                                  const Main_Ctrl_PositionGlobal_Request* request,
                                  Main_Ctrl_PositionGlobal_Reply* reply) override {
    reply->set_message("CMD : PositionGlobal : Accept");

    ServerUnaryReactor* reactor = context->DefaultReactor();
    reactor->Finish(Status::OK);
    return reactor;
  }
  ServerUnaryReactor* Ctrl_PositionNED(CallbackServerContext* context,
                                  const Main_Ctrl_PositionNED_Request* request,
                                  Main_Ctrl_PositionNED_Reply* reply) override {
    reply->set_message("CMD : PositionNED : Accept");

    ServerUnaryReactor* reactor = context->DefaultReactor();
    reactor->Finish(Status::OK);
    return reactor;
  }
};

void RunServer(uint16_t port) {
  std::string server_address = "127.0.0.1:" + std::to_string(port);
  GreeterServiceImpl service;

  grpc::EnableDefaultHealthCheckService(true);
  grpc::reflection::InitProtoReflectionServerBuilderPlugin();
  ServerBuilder builder;

  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());

  builder.RegisterService(&service);

  std::unique_ptr<Server> server(builder.BuildAndStart());
  std::cout << "Server listening on " << server_address << std::endl;

  server->Wait();
}

int main(int argc, char** argv) {
  RunServer(8081);

  return 0;
}
